/*
 *
 *
 */

#ifndef USER_PASSWORD_DYNAMIC_H
#define USER_PASSWORD_DYNAMIC_H

#include "gkt_types.h"
#include "gkt_debug.h"

#ifdef __cplusplus
extern "C" {
#endif

#define USER_DYNPWD_BASE_YEAR	2020

#define USER_DYNPWD_KEY_DIGITS_MAXSIZE	10
#define USER_DYNPWD_KEY_UNITS_MAXSIZE	16
#define USER_DYNPWD_DATA_UNITS_MAXSIZE	16

#define USER_DYNPWD_DIGITS_MINSIZE	12
#define USER_DYNPWD_DIGITS_MAXSIZE	15

enum {
	USER_DYNPWD_TYPE_NOTS = 0,	/* number of times */
	USER_DYNPWD_TYPE_EDTQ,	/* expire date & time quantum */
	USER_DYNPWD_TYPE_SDED,	/* start date & expire date */
	USER_DYNPWD_TYPE_MAX
};

/************************************************************
 * original data struct
 * LSB                                MSB
 * | <--  GENERAL --> |                 |
 * |-------------------------------------
 * | TYPE | CANCELLED | PRIVATE OF TYPE |
 * |  (2) |    (1)    |     (4m + 1)    | <unit in bits>
 * |------------------------------------|
 * TOTAL BITS: N * 4
 *
 *
 * data units after units-build
 * |-----------------------------------|
 * | U-0 | U-1 |  ... ... ...  | U-N-1 |
 * |-----------------------------------|
 * TOTAL UNITS: N
 *
 * data units after confuse
 * |--------------------------------------------|
 * | U'-0 | U'-1 | ... ... ...  | U'-N-1 | U'-N |
 * |--------------------------------------------|
 * TOTAL UNITS: N + 1
 *
 * data units after encrypt
 * |----------------------------------------------------|
 * | U"-0 | U"-1 | ... ... ... | U"-N-1 | U"-N | U"-N+1 |
 * |----------------------------------------------------|
 * TOTAL UNITS: N + 2 
 *
 * digits after u2d convert
 *   like - "7162 3746 1824 9"
 ************************************************************/

/* general part */

#define USER_DYNPWD_TYPE_BITS	2
#define USER_DYNPWD_FLAG_CANCEL_BITS	1
#define USER_DYNPWD_GENERAL_BITS	\
	(USER_DYNPWD_TYPE_BITS + USER_DYNPWD_FLAG_CANCEL_BITS)

#define USER_DYNPWD_GENERAL_SHIFT	0

#define USER_DYNPWD_TYPE_SHIFT	USER_DYNPWD_GENERAL_SHIFT
#define USER_DYNPWD_TYPE_MASK	\
	((1U << USER_DYNPWD_TYPE_BITS) - 1)

#define USER_DYNPWD_FLAG_CANCEL_SHIFT	\
	(USER_DYNPWD_TYPE_SHIFT + USER_DYNPWD_TYPE_BITS)
#define USER_DYNPWD_FLAG_CANCEL_MASK	\
	(1U << USER_DYNPWD_FLAG_CANCEL_SHIFT)
#define USER_DYNPWD_FLAG_CANCEL	\
	(1U << USER_DYNPWD_FLAG_CANCEL_SHIFT)

typedef struct _user_dynpwd_data	user_dynpwd_data_s;

#include "user_password_dynamic_totp.h"
#include "user_password_dynamic_nots.h"
#include "user_password_dynamic_edtq.h"
#include "user_password_dynamic_sded.h"
#include "user_password_dynamic_algo.h"

struct _user_dynpwd_data {
	uint32_t	type;
	int	cancel;
	union {
		user_dynpwd_nots_data_s	nots;
		user_dynpwd_edtq_data_s	edtq;
		user_dynpwd_sded_data_s	sded;
	};
};

/* item */
struct _user_dynpwd_item {
	user_item_extend_header_u	ext_header;

	union {
		user_dynpwd_nots_item_data_s	nots;
		user_dynpwd_edtq_item_data_s	edtq;
		user_dynpwd_sded_item_data_s	sded;
	};
} __ALIGNED(USER_ALIGNMENT);
typedef struct _user_dynpwd_item	user_dynpwd_item_s;
#define USER_DYNPWD_ITEM_SIZE	sizeof(user_dynpwd_item_s)

#define USER_DYNPWD_ITEM_C(item_index)	\
	(const user_dynpwd_item_s *)USER_ITEM_HEADER_C(&g_user_dynpwd.instance, item_index)

typedef struct _user_dynpwd {
	user_instance_s	instance;
	user_dynpwd_item_s	save_item;
	uint32_t	next_seq;
} user_dynpwd_s;
extern user_dynpwd_s g_user_dynpwd;

typedef struct _user_dynpwd_info {
	uint16_t	admin_item_indexs[GKT_USER_PASSWORD_ADMIN_MAXNUMS];
#if USER_DYNPWD_TOTP_ENABLE
	uint32_t	totp_last_steps[GKT_USER_PASSWORD_ADMIN_MAXNUMS];
#endif
} user_dynpwd_info_s;
extern __RETMEM_USR user_dynpwd_info_s g_user_dynpwd_info;


typedef int (*user_dynpwd_retrieve_fn)(user_dynpwd_data_s *data,
				uint32_t *values);
typedef int (*user_dynpwd_verify_fn)(user_dynpwd_data_s *data,
				uint32_t admin_user_index);
typedef struct _user_dynpwd_instance {
	uint32_t	units_size;
	user_dynpwd_retrieve_fn	retrieve;
	user_dynpwd_verify_fn	verify;
} user_dynpwd_instance_s;
#define USER_DYNPWD_INSTANCE_DEFINE(NAME)	\
	[USER_DYNPWD_TYPE_##NAME] = {	\
		.units_size = USER_DYNPWD_##NAME##_TOTAL_UNITS,	\
		.retrieve	= user_dynpwd_##NAME##_retrieve,	\
		.verify	= user_dynpwd_##NAME##_verify,	\
	}

int user_dynpwd_add_info(uint32_t item_index);
void user_dynpwd_delete_info(uint32_t item_index);
void user_dynpwd_reset_info(void);

int user_dynpwd_reload_items_v(void);
int user_dynpwd_save_item(user_dynpwd_item_s *v_item,
			uint8_t state);
void user_dynpwd_delete_item(uint32_t item_index);

void user_dynpwd_reset_partition(void);

int user_dynpwd_verify(uint32_t *user_id, 
		const uint8_t *digits, uint32_t digits_len);

int user_dynpwd_init(void);

#ifdef __cplusplus
}
#endif

#endif	/* USER_PASSWORD_DYNAMIC_H */

